package com.apache.gateway.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.apache.api.vo.ResultMsg;
import com.apache.gateway.config.HttpService;
import com.apache.gateway.config.JedisUtil;
import com.apache.gateway.config.Response;
import com.apache.gateway.route.DynamicRouteService;
import com.apache.tools.ConfigUtil;
import com.apache.tools.PropertiesConfig;
import com.apache.tools.StrUtil;
import com.apache.tools.UUIDUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.ResponseCookie;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;

import org.springframework.http.server.reactive.ServerHttpRequest;
import reactor.core.publisher.Mono;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * @description: 图片验证码
 * @author: Hou Dayu
 * @date: Created in 2020/8/4
 */
@Controller
public class AuthCodeImgController {

    private static final String SESSION_KEY_OF_RAND_CODE = "randCode";
    private static final int count = 200;
    private static final int width = 105;
    private static final int height = 35;
    private static final int lineWidth = 2;
	
    @Autowired
    private JedisUtil jedisUtil;

    @RequestMapping(value={"/uniteAuth/randCode"},method = {RequestMethod.GET, RequestMethod.POST})
    public Mono<Void> getAuthCode(ServerHttpRequest request, ServerHttpResponse response) throws IOException {
        // 在内存中创建图象
        final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // 获取图形上下文
        final Graphics2D graphics = (Graphics2D) image.getGraphics();
        // 设定背景颜色
        graphics.setColor(Color.WHITE); // ---1
        graphics.fillRect(0, 0, width, height);
        // 设定边框颜色
        graphics.drawRect(0, 0, width - 1, height - 1);

        final Random random = new Random();
        // 随机产生干扰线，使图象中的认证码不易被其它程序探测到
        for (int i = 0; i < count; i++) {
            graphics.setColor(getRandColor(150, 200)); // ---3

            final int x = random.nextInt(width - lineWidth - 1) + 1; // 保证画在边框之内
            final int y = random.nextInt(height - lineWidth - 1) + 1;
            final int xl = random.nextInt(lineWidth);
            final int yl = random.nextInt(lineWidth);
            graphics.drawLine(x, y, x + xl, y + yl);
        }
        // 取随机产生的认证码(4位数字)
        final String resultCode = exctractRandCode();
        for (int i = 0; i < resultCode.length(); i++) {
            // 设置字体颜色
            graphics.setColor(Color.BLACK);
            // 设置字体样式
            graphics.setFont(new Font("Times New Roman", Font.BOLD, 24));
            // 设置字符，字符间距，上边距
            graphics.drawString(String.valueOf(resultCode.charAt(i)), (23 * i) + 8, 26);
        }
        String randCodeKey = UUIDUtil.getUUID("",32);
        jedisUtil.buildCacheInfo(randCodeKey,resultCode,600);//10分钟
        ResponseCookie.ResponseCookieBuilder cookie = ResponseCookie.from("__guuid",randCodeKey);
        cookie.path("/");
        cookie.maxAge(600);
        cookie.httpOnly(true);
        response.addCookie(cookie.build());
        graphics.dispose();
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ImageIO.write(image, "jpg", byteArrayOutputStream);
        //定义响应值，写入byte
        byte[] bytes = byteArrayOutputStream.toByteArray();
        DataBuffer bodydataBuffer = response.bufferFactory().wrap(bytes);
        return response.writeWith(Mono.just(bodydataBuffer));
    }

    @GetMapping("/fallback")
    public Response fallback() {
        Response response = new Response();
        response.setCode("100");
        response.setMessage("服务暂时不可用");
        return response;
    }

    @RequestMapping(value={"/serverList","/toLine","/info"},method = {RequestMethod.GET, RequestMethod.POST})
    public Mono<Void> sendEurekaDatas(ServerHttpRequest request, ServerHttpResponse response){
        String respData="";
        String reqType = request.getPath().value();
        String eurekaUrl = PropertiesConfig.getApplicatinConfig("eureka.manager.url")+reqType;
        Map bodyParams = null;
        if("/toLine".equals(reqType)) {
            bodyParams = new HashMap();
            String url = request.getQueryParams().getFirst("url");
            String type = request.getQueryParams().getFirst("type");
            String serverId = request.getQueryParams().getFirst("serverId");
            bodyParams.put("url",url);
            bodyParams.put("type",type);
            bodyParams.put("serverId",serverId);
            if(HttpService.isNotNull(request.getQueryParams().getFirst("tokenId"))) {
                bodyParams.put("tokenId",request.getQueryParams().getFirst("tokenId"));
            }
            respData = HttpService.sendPostHttp(eurekaUrl, bodyParams);
        } else if("/info".equals(reqType)) {
            JSONObject info = new JSONObject();
            info.put("name",PropertiesConfig.getApplicatinConfig("info.app.name"));
            info.put("description",PropertiesConfig.getApplicatinConfig("info.app.description"));
            info.put("version",PropertiesConfig.getApplicatinConfig("info.app.version"));
            info.put("spring-boot-version",PropertiesConfig.getApplicatinConfig("info.app.spring-boot-version"));
            JSONObject app = new JSONObject();
            app.put("app",info);
            respData = app.toString();
        } else {
            respData = HttpService.sendGetHttp(eurekaUrl, bodyParams);
        }
        if(StrUtil.isNull(respData)){
            respData= JSON.toJSONString(new ResultMsg("F","操作失败"));
        }
        DataBuffer bodydataBuffer = response.bufferFactory().wrap(respData.getBytes());
        return response.writeWith(Mono.just(bodydataBuffer));
    }

    private String exctractRandCode() {
        String randCodeType = StrUtil.doNull(ConfigUtil.getInstance().getValueByKey("randCodeType"), "1");
        int randCodeLength = 4;
        if (randCodeType == null) {
            return RandCodeImageEnum.NUMBER_CHAR.generateStr(randCodeLength);
        } else {
            switch(randCodeType.charAt(0)) {
                case '1':
                    return RandCodeImageEnum.NUMBER_CHAR.generateStr(randCodeLength);
                case '2':
                    return RandCodeImageEnum.LETTER_CHAR.generateStr(randCodeLength);
                case '3':
                    return RandCodeImageEnum.ALL_CHAR.generateStr(randCodeLength);
                default:
                    return RandCodeImageEnum.NUMBER_CHAR.generateStr(randCodeLength);
            }
        }
    }

    private Color getRandColor(int fc, int bc) {
        Random random = new Random();
        if (fc > 255) {
            fc = 255;
        }
        if (bc > 255) {
            bc = 255;
        }
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }

    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (StrUtil.isNotNull(ip) && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值，第一个ip才是真实ip
            if (ip.indexOf(",") != -1) {
                ip = ip.split(",")[0];
            }
        }
        if (StrUtil.isNull(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (StrUtil.isNull(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StrUtil.isNull(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (StrUtil.isNull(ip)|| "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (StrUtil.isNull(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (StrUtil.isNull(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    protected  enum RandCodeImageEnum {
        ALL_CHAR("123456789abcdefghijklmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ"),
        LETTER_CHAR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"),
        NUMBER_CHAR("0123456789");

        private String charStr;

        private RandCodeImageEnum(String charStr) {
            this.charStr = charStr;
        }

        public String generateStr(int codeLength) {
            StringBuilder sb = new StringBuilder();
            Random random = new Random();
            String sourseStr = this.getCharStr();

            for(int i = 0; i < codeLength; ++i) {
                sb.append(sourseStr.charAt(random.nextInt(sourseStr.length())));
            }
            return sb.toString();
        }

        public String getCharStr() {
            return this.charStr;
        }
    }
}
